package FinalWork;

import java.applet.Applet;
import java.awt.*;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;

import javax.media.j3d.*;
import javax.vecmath.*;

import com.sun.j3d.utils.behaviors.mouse.*;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

class Algorithm {
    public static Matrix3f createRotationMatrix(Vector3f eulerAngles) {
        float pitch = eulerAngles.x;
        float yaw = eulerAngles.y;
        float roll = eulerAngles.z;

        Matrix3f rotationX = new Matrix3f();
        rotationX.rotX(pitch);

        Matrix3f rotationY = new Matrix3f();
        rotationY.rotY(yaw);

        Matrix3f rotationZ = new Matrix3f();
        rotationZ.rotZ(roll);

        Matrix3f rotationMatrix = new Matrix3f();
        rotationMatrix.set(rotationZ);
        rotationMatrix.mul(rotationY);
        rotationMatrix.mul(rotationX);

        return rotationMatrix;
    }
};

class BezierSurface extends Shape3D {
    public BezierSurface(Vector3f[][] controlPoints) {
        int precision = 25;

        Appearance app = new Appearance();
        PolygonAttributes polygon = new PolygonAttributes();
        polygon.setCullFace(PolygonAttributes.CULL_NONE);
        app.setPolygonAttributes(polygon);
        ColoringAttributes color = new ColoringAttributes();
        color.setColor(0.8f, 0.8f, 0.8f);
        app.setColoringAttributes(color);

        int triangleCount = (precision - 1) * (precision - 1) * 2;
        Vector3f[] points = new Vector3f[precision * precision];
        Vector3f[] interpolatedControlPoints = new Vector3f[4];
        for (int i = 0; i < precision; ++i)
        {
            float t1 = (float) (i) / precision;
            for (int j = 0; j < 4; ++j)
            {
                interpolatedControlPoints[j] = calculateCubicBezierPoint(controlPoints[j], t1);
            }
            for (int j = 0; j < precision; ++j)
            {
                float t2 = (float) (j) / precision;
                points[j + i * precision] = calculateCubicBezierPoint(interpolatedControlPoints, t2);
            }
        }

        TriangleArray vertices = new TriangleArray(triangleCount * 3, GeometryArray.COORDINATES | GeometryArray.NORMALS);

        int index = 0;
        for (int i = 0; i < precision - 1; ++i)
        {
            for (int j = 0; j < precision - 1; ++j)
            {
                Vector3f p0 = points[j + i * precision];
                Vector3f p1 = points[j + 1 + i * precision];
                Vector3f p2 = points[j + (i + 1) * precision];
                Vector3f p3 = points[j + 1 + (i + 1) * precision];

                Vector3f e01 = new Vector3f(p1.x - p0.x, p1.y - p0.y, p1.z - p0.z);
                Vector3f e02 = new Vector3f(p2.x - p0.x, p2.y - p0.y, p2.z - p0.z);
                Vector3f e13 = new Vector3f(p3.x - p1.x, p3.y - p1.y, p3.z - p1.z);
                Vector3f e12 = new Vector3f(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);

                Vector3f n0 = new Vector3f();
                n0.cross(e01, e02);
                n0.normalize();

                Vector3f n1 = new Vector3f();
                n1.cross(e13, e12);
                n1.normalize();

                vertices.setCoordinate(index, new Point3f(p0.x, p0.y, p0.z));
                vertices.setCoordinate(index + 1, new Point3f(p2.x, p2.y, p2.z));
                vertices.setCoordinate(index + 2, new Point3f(p1.x, p1.y, p1.z));
                vertices.setCoordinate(index + 3, new Point3f(p2.x, p2.y, p2.z));
                vertices.setCoordinate(index + 4, new Point3f(p3.x, p3.y, p3.z));
                vertices.setCoordinate(index + 5, new Point3f(p1.x, p1.y, p1.z));

                vertices.setNormal(index, n0);
                vertices.setNormal(index + 1, n0);
                vertices.setNormal(index + 2, n0);
                vertices.setNormal(index + 3, n1);
                vertices.setNormal(index + 4, n1);
                vertices.setNormal(index + 5, n1);

                index += 6;
            }
        }

        Material material = new Material();
        material.setAmbientColor(new Color3f(0.2f, 0.2f, 0.2f));
        material.setDiffuseColor(new Color3f(0.8f, 0.8f, 0.8f));
        material.setSpecularColor(new Color3f(0.9f, 0.9f, 0.9f));
        material.setShininess(64.0f);
        app.setMaterial(material);

        this.addGeometry(vertices);
        this.setAppearance(app);
    }

    Vector3f calculateCubicBezierPoint(Vector3f[] ps, float t)
    {
        double u = 1.0 - t;
        double tt = t * t;
        double uu = u * u;
        double uuu = uu * u;
        double ttt = tt * t;
        double uut = uu * t;
        double ttu = tt * u;

        Vector3f point = new Vector3f();
        point.x = (float) (uuu * ps[0].x + 3.0 * uut * ps[1].x + 3.0 * ttu * ps[2].x + ttt * ps[3].x);
        point.y = (float) (uuu * ps[0].y + 3.0 * uut * ps[1].y + 3.0 * ttu * ps[2].y + ttt * ps[3].y);
        point.z = (float) (uuu * ps[0].z + 3.0 * uut * ps[1].z + 3.0 * ttu * ps[2].z + ttt * ps[3].z);

        return point;
    }
};

public class Main extends Applet {
    public BranchGroup createBranchGroupSceneGraph() {
        BranchGroup BranchGroupRoot = new BranchGroup();
        BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
        Color3f bgColor = new Color3f(1.0f, 1.0f, 1.0f);
        Background bg = new Background(bgColor);
        bg.setApplicationBounds(bounds);
        BranchGroupRoot.addChild(bg);
        Color3f directionalColor = new Color3f(1.0f, 1.0f, 1.0f);
        Vector3f vec = new Vector3f(0.f, -1.f, 0.0f);
        DirectionalLight directionalLight = new DirectionalLight(directionalColor, vec);
        directionalLight.setInfluencingBounds(bounds);
        BranchGroupRoot.addChild(directionalLight);

        TransformGroup maintransformgroup = new TransformGroup();
        maintransformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        maintransformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        MouseRotate mouserotate = new MouseRotate();
        mouserotate.setTransformGroup(maintransformgroup);
        BranchGroupRoot.addChild(mouserotate);
        mouserotate.setSchedulingBounds(bounds);
        MouseZoom mousezoom = new MouseZoom();
        mousezoom.setTransformGroup(maintransformgroup);
        BranchGroupRoot.addChild(mousezoom);
        mousezoom.setSchedulingBounds(bounds);
        MouseTranslate mousetranslate = new MouseTranslate();
        mousetranslate.setTransformGroup(maintransformgroup);
        BranchGroupRoot.addChild(mousetranslate);
        mousetranslate.setSchedulingBounds(bounds);

        Transform3D mainTransform = new Transform3D();
        mainTransform.setScale(0.5);
        maintransformgroup.setTransform(mainTransform);

        String filePath = "C:\\Users\\Administrator\\Desktop\\bseditor\\assets\\models\\saved4.bsm";

        // 读取BSM文件并解析数据
        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;

            // 循环读取每一行
            while ((line = reader.readLine()) != null) {
                // 以空格分隔数据
                String[] values = line.split(" ");

                // 解析控制点信息
                Vector3f[][] controlPoints = new Vector3f[4][4];
                int index = 0;

                for (int i = 0; i < 4; ++i) {
                    for (int j = 0; j < 4; ++j) {
                        float x = Float.parseFloat(values[index++]);
                        float y = Float.parseFloat(values[index++]);
                        float z = Float.parseFloat(values[index++]);
                        controlPoints[i][j] = new Vector3f(x, y, z);
                    }
                }

                // 解析位置、旋转和缩放信息
                float posX = Float.parseFloat(values[index++]);
                float posY = Float.parseFloat(values[index++]);
                float posZ = Float.parseFloat(values[index++]);

                float rotX = Float.parseFloat(values[index++]);
                float rotY = Float.parseFloat(values[index++]);
                float rotZ = Float.parseFloat(values[index++]);

                float scaleX = Float.parseFloat(values[index++]);
                float scaleY = Float.parseFloat(values[index++]);
                float scaleZ = Float.parseFloat(values[index]);

                TransformGroup transformgroup = new TransformGroup();

                Transform3D transform3D = new Transform3D();
                transform3D.setTranslation(new Vector3f(posX, posY, posZ));
                transform3D.setRotation(Algorithm.createRotationMatrix(new Vector3f(rotX, rotY, rotZ)));
                transform3D.setScale(new Vector3d(scaleX, scaleY, scaleZ));
                transformgroup.setTransform(transform3D);

                transformgroup.addChild(new BezierSurface(controlPoints));
                maintransformgroup.addChild(transformgroup);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        BranchGroupRoot.addChild(maintransformgroup);
        BranchGroupRoot.compile();
        return BranchGroupRoot;
    }

    public Main() {
        setLayout(new BorderLayout());
        GraphicsConfiguration gc = SimpleUniverse.getPreferredConfiguration();
        Canvas3D c = new Canvas3D(gc);
        add("Center", c);
        BranchGroup BranchGroupScene = createBranchGroupSceneGraph();
        SimpleUniverse u = new SimpleUniverse(c);
        u.getViewingPlatform().setNominalViewingTransform();
        u.addBranchGraph(BranchGroupScene);
    }

    public static void main(String[] args) {
        new MainFrame(new Main(), 800, 800);
    }
}